package com.gjy.util;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTValidator;
import cn.hutool.jwt.signers.JWTSignerUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;

/**
 * @author 宫静雨
 * @version 1.0
 * @since 2022-09-28 08:47:53
 */
@Component
public class JwtUtils {

    @Value("${custom.jwt.key}")
    private String key;

    @Value("${custom.jwt.expire}")
    private Integer expire;

    /**
     * 创建一个 token
     *
     * @return token
     */
    public String createToken(String id) {
        JWT jwt = JWT.create();
        jwt.setPayload("id", id);
        DateTime now = DateTime.now();
        long start = now.getTime();
        long end = now.offsetNew(DateField.HOUR, expire).getTime();
        return jwt
                .setKey(key.getBytes(StandardCharsets.UTF_8))
                .setPayload(JWTPayload.ISSUED_AT, start)
                .setPayload(JWTPayload.EXPIRES_AT, end)
                .sign();
    }

    /**
     * 获取 jwt-token 中payload的某个值
     *
     * @param token   jwt-token
     * @param payload payload
     * @return payload value
     */
    public Object parseToken(String token, String payload) {
        return JWT.of(token)
                .getPayload(payload);
    }

    /**
     * 验证一个 token 是否正确
     *
     * @param token jwt-token
     * @return 是否合法
     */
    public boolean verifyToken(String token) {
        return JWT.of(token)
                .setKey(key.getBytes(StandardCharsets.UTF_8))
                .verify();
    }

    /**
     * 验证算法
     * 算法的验证包括两个方面
     * <p>
     * 1. 验证header中算法ID和提供的算法ID是否一致
     * 2. 调用JWT.verify验证token是否正确
     *
     * @param token jwt-token
     * @return 算法是否合法
     */
    public boolean validateAlgorithm(String token) {
        JWTValidator.of(token)
                .validateAlgorithm(JWTSignerUtil.hs256(key.getBytes(StandardCharsets.UTF_8)));
        return true;
    }

    /**
     * 验证时间
     * 对于时间类载荷，有单独的验证方法，主要包括：
     * <p>
     * 生效时间（JWTPayload#NOT_BEFORE）不能晚于当前时间
     * 失效时间（JWTPayload#EXPIRES_AT）不能早于当前时间
     * 签发时间（JWTPayload#ISSUED_AT）不能晚于当前时间
     * 一般时间线是：
     * <p>
     * (签发时间)---------(生效时间)---------(当前时间)---------(失效时间)
     * <p>
     * 签发时间和生效时间一般没有前后要求，都早于当前时间即可。
     *
     * @param token jwt-token
     * @return 算法是否合法
     */
    public boolean validateDate(String token) {
        JWT jwt = JWT.of(token)
                .setKey(key.getBytes(StandardCharsets.UTF_8));
        long startTime = (long) jwt.getPayload(JWTPayload.ISSUED_AT);
        long endTime = (long) jwt.getPayload(JWTPayload.EXPIRES_AT);

        long now = DateTime.now().getTime();
        return (startTime < now) && (now < endTime);
    }

    /**
     * 续签 token
     *
     * @param token token
     */
    public String renew(String token) {
        JWT jwt = JWT.of(token)
                .setKey(key.getBytes(StandardCharsets.UTF_8));
        String id = (String) jwt.getPayload("id");
        return createToken(id);
    }

    /**
     * 是否需要续签
     *
     * @param token token
     * @return true/false
     */
    public boolean hasRenew(String token) {
        JWT jwt = JWT.of(token)
                .setKey(key.getBytes(StandardCharsets.UTF_8));
        long endTime = (long) jwt.getPayload(JWTPayload.EXPIRES_AT);
        DateTime endDateTime = DateTime.of(endTime);
        DateTime nowDateTime = DateTime.now();
        // 计算两个日期之间的差值
        long between = DateUtil.between(nowDateTime, endDateTime, DateUnit.HOUR);
        // 大于6小时返回true，不操作
        // 小于6小时返回false，进行续签
//        return (expire - Constant.RENEW_TIME) <= between;
        return (expire - 18) <= between;
    }
}